package com.itheima.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.article.feign.ApArticleFeign;
import com.itheima.behaviour.dto.FollowBehaviorDto;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.constants.SystemConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.AppJwtUtil;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.LoginResultVO;
import com.itheima.common.vo.ResultVo;
import com.itheima.user.dto.LoginDto;
import com.itheima.user.dto.UserRelationDto;
import com.itheima.user.mapper.ApUserFanMapper;
import com.itheima.user.mapper.ApUserFollowMapper;
import com.itheima.user.mapper.ApUserMapper;
import com.itheima.user.pojo.ApUser;
import com.itheima.user.pojo.ApUserFan;
import com.itheima.user.pojo.ApUserFollow;
import com.itheima.user.service.ApUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @description <p>APP用户信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.user.service.impl
 */
@Service
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {

    @Resource
    private ApUserFollowMapper apUserFollowMapper;

    @Resource
    private ApUserFanMapper apUserFanMapper;

    @Resource
    private ApArticleFeign apArticleFeign;

    @Resource
    private KafkaTemplate kafkaTemplate;

    /**
     * App端登录校验
     *
     * @param dto
     * @return
     */
    @Override
    public LoginResultVO loginCheck(LoginDto dto) {
        //0. 获取手机号码、密码
        String phone = dto.getPhone();
        String password = dto.getPassword();
        //1. 区分是匿名登录
        Long loginUserId = SystemConstants.ANONYMOUS_USER_ID;
        LoginResultVO vo = new LoginResultVO();
        if(!StringUtils.isEmpty(phone)){
            // 手机号码不为空, 如果密码为空则报错
            if(StringUtils.isEmpty(password)){
                throw new LeadNewsException("密码不能为空!");
            }
            //2. 是用手机号码与密码 都有值
            //3. 使用手机号码查询用户信息
            ApUser loginUser = query().eq("phone", phone).one();
            //3.1. 用户不存在则报 手机号码或密码错误
            if(null == loginUser){
                throw new LeadNewsException("手机号码或密码错误");
            }
            //判断用户的状态
            if(loginUser.getStatus() == 1) { // 用户状态被锁定
                throw new LeadNewsException("用户已被锁定，请联系客服解锁!");
            }
            //3.2. 对前端的密码+盐 再加密
            password = DigestUtils.md5DigestAsHex((password+loginUser.getSalt()).getBytes());
            //3.3. 比较前端的密码与数据库的密码是否相同
            if(!password.equals(loginUser.getPassword())) {
                //3.4. 不同则报错
                throw new LeadNewsException("手机号码或密码错误");
            }
            loginUserId = loginUser.getId();
            //  注意数据脱敏处理
            loginUser.setPassword(null);
            loginUser.setSalt(null);
            vo.setUser(loginUser);
        }
        //4. 生成token  注意数据脱敏处理
        String token = AppJwtUtil.createToken(loginUserId);
        //5. 构建返回结果
        vo.setToken(token);
        return vo;
    }

    /**
     * 关注与取消关注
     *
     * @param dto
     */
    @Override
    @Transactional
    public void userFollow(UserRelationDto dto) {
        //1. 提出参数
        Integer operation = dto.getOperation();
        Long authorId = dto.getAuthorId();
        Long loginUserId = RequestContextUtil.getUserId();
        if(SystemConstants.ANONYMOUS_USER_ID == loginUserId){
            // 匿名登录
            throw new LeadNewsException(HttpCodeEnum.NEED_LOGIN);
        }
        //2. 判断操作类型
        ApUserFollow apUserFollow = findByUserIdAuthorId(loginUserId, authorId);
        if(operation == 0) {
            //3. 关注行为
            //3.1 判断是否已经关注过了，关注过了则报错
            if(null != apUserFollow){
                throw new LeadNewsException("已经关注过了!");
            }
            //3.2 没关注过，则添加关注
            //3.2.1 添加关注表
            addUserFollow(dto);
            //  远程调用查询作者的名称
            //3.2.2 添加粉丝表
            addUserFan(authorId);

            //发消息给kafka，同步行为信息
            FollowBehaviorDto followBehaviorDto=new FollowBehaviorDto();
            followBehaviorDto.setUserId(loginUserId);
            followBehaviorDto.setFollowId(authorId);
            followBehaviorDto.setArticleId(dto.getArticleId());
            followBehaviorDto.setEquipmentId(88888);
            kafkaTemplate.send(BusinessConstants.MqConstants.FOLLOW_BEHAVIOR_TOPIC, JSON.toJSONString(followBehaviorDto));
        }else {
            //4. 取消关注
            //4.1 判断是否关注过了，没关注则报错
            if(null == apUserFollow){
                throw new LeadNewsException("还没有关注该作者！");
            }
            //4.2 关注过则要删除关注表
            removeUserFollow(authorId);
            //4.3 删除粉丝表
            removeUserFan(authorId);
        }
        //5. 事务控制
    }

    /**
     * 删除粉丝记录
     * @param authorId
     */
    private void removeUserFan(Long authorId) {
        LambdaQueryWrapper<ApUserFan> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFan::getFansId, RequestContextUtil.getUserId());
        lqw.eq(ApUserFan::getUserId, authorId);

        apUserFanMapper.delete(lqw);
    }

    /**
     * 删除关注记录
     * @param authorId
     */
    private void removeUserFollow(Long authorId) {
        LambdaQueryWrapper<ApUserFollow> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFollow::getUserId, RequestContextUtil.getUserId());
        lqw.eq(ApUserFollow::getFollowId, authorId);

        apUserFollowMapper.delete(lqw);
    }

    /**
     * 添加粉丝记录
     * @param authorId
     */
    private void addUserFan(Long authorId) {
        ApUserFan apUserFan = new ApUserFan();
        apUserFan.setUserId(authorId);
        // 登录用户成了 作者的粉丝
        Long loginUserId = RequestContextUtil.getUserId();
        apUserFan.setFansId(loginUserId);
        ApUser loginUser = getById(loginUserId);
        apUserFan.setFansName(loginUser.getName());
        apUserFan.setLevel(0);// 粉丝忠诚度 正常
        apUserFan.setCreatedTime(LocalDateTime.now());
        apUserFan.setIsDisplay(1);
        apUserFan.setIsShieldLetter(0); // 不要屏蔽私信
        apUserFan.setIsShieldComment(0);// 不要屏蔽评论

        apUserFanMapper.insert(apUserFan);
    }

    private void addUserFollow(UserRelationDto dto) {
        ApUserFollow apUserFollow = new ApUserFollow();
        apUserFollow.setUserId(RequestContextUtil.getUserId());
        apUserFollow.setFollowId(dto.getAuthorId());
        apUserFollow.setLevel(0);// 偶尔感兴趣
        apUserFollow.setIsNotice(1);// 要通知
        apUserFollow.setCreatedTime(LocalDateTime.now());

        // 作者名称
        ResultVo<String> result = apArticleFeign.getAuthorNameByArticleId(dto.getArticleId());
        if(!result.isSuccess()){
            log.error("远程调用文章微查询作者名称失败! {}", result.getErrorMessage());
            throw new LeadNewsException("添加关注失败，请稍候重试!");
        }
        apUserFollow.setFollowName(result.getData());
        apUserFollowMapper.insert(apUserFollow);
    }


    private ApUserFollow findByUserIdAuthorId(Long loginUserId, Long authorId) {
        LambdaQueryWrapper<ApUserFollow> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFollow::getUserId, loginUserId);
        lqw.eq(ApUserFollow::getFollowId, authorId);
        return apUserFollowMapper.selectOne(lqw);
    }
}
